﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="PropertyComparer.cs" company="Elilink">
//   Defor
// </copyright>
// <summary>
//   Class PropertyComparer
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace BusinessLayer.Tools
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Reflection;

    /// <summary>
    ///     Class PropertyComparer
    /// </summary>
    /// <typeparam name="T">Type of the property to be compared</typeparam>
    public class PropertyComparer<T> : IComparer<T>
    {
        #region Fields

        /// <summary>
        ///     The _comparer
        /// </summary>
        private readonly IComparer _comparer;

        /// <summary>
        ///     The _property descriptor
        /// </summary>
        private PropertyDescriptor _propertyDescriptor;

        /// <summary>
        ///     The _reverse
        /// </summary>
        private int _reverse;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="PropertyComparer{T}" /> class.
        /// </summary>
        /// <param name="property">
        ///     The property.
        /// </param>
        /// <param name="direction">
        ///     The direction.
        /// </param>
        public PropertyComparer(PropertyDescriptor property, ListSortDirection direction)
        {
            _propertyDescriptor = property;
            Type comparerForPropertyType = typeof(Comparer<>).MakeGenericType(property.PropertyType);
            _comparer =
                (IComparer)
                comparerForPropertyType.InvokeMember(
                    "Default", 
                    BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.Public, 
                    null, 
                    null, 
                    null);
            SetListSortDirection(direction);
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        ///     Compares two objects and returns a value indicating whether one is less than, equal to, or greater than the other.
        /// </summary>
        /// <param name="x">
        ///     The first object to compare.
        /// </param>
        /// <param name="y">
        ///     The second object to compare.
        /// </param>
        /// <returns>
        ///     Value
        ///     Condition
        ///     Less than zero
        ///     <paramref name="x" /> is less than <paramref name="y" />.
        ///     Zero
        ///     <paramref name="x" /> equals <paramref name="y" />.
        ///     Greater than zero
        ///     <paramref name="x" /> is greater than <paramref name="y" />.
        /// </returns>
        public int Compare(T x, T y)
        {
            return _reverse * _comparer.Compare(_propertyDescriptor.GetValue(x), _propertyDescriptor.GetValue(y));
        }

        /// <summary>
        ///     Sets the property and direction.
        /// </summary>
        /// <param name="descriptor">
        ///     The descriptor.
        /// </param>
        /// <param name="direction">
        ///     The direction.
        /// </param>
        public void SetPropertyAndDirection(PropertyDescriptor descriptor, ListSortDirection direction)
        {
            SetPropertyDescriptor(descriptor);
            SetListSortDirection(direction);
        }

        #endregion

        #region Methods

        /// <summary>
        ///     Sets the list sort direction.
        /// </summary>
        /// <param name="direction">
        ///     The direction.
        /// </param>
        private void SetListSortDirection(ListSortDirection direction)
        {
            _reverse = direction == ListSortDirection.Ascending ? 1 : -1;
        }

        /// <summary>
        ///     Sets the property descriptor.
        /// </summary>
        /// <param name="descriptor">
        ///     The descriptor.
        /// </param>
        private void SetPropertyDescriptor(PropertyDescriptor descriptor)
        {
            _propertyDescriptor = descriptor;
        }

        #endregion
    }
}